

#ifndef CORNERGRID_H_
#define CORNERGRID_H_

#include "BinInput.h"
#include "SparseVector.h"
#include "TypeCast.h"
#include "omp.h"

#include "Dream3DRender.h"
#include <vsg/all.h>

#include "mymath.h"
#include <QThread>
#include <unordered_map>

using namespace std;
using namespace vsg;

// 根据4个顶点索引计算唯一一个编码
size_t hashCombine(size_t a, size_t b, size_t c, size_t d);

/*
      7--------6
     /|       /|
    4--------5 |
    | |      | |
    | 3------|-2
    |/       |/
    0--------1
*/
// 6面体的单个面片
struct QuadID
{
  // a b c d 顺序
  // 4个顶点索引
  size_t a;
  size_t b;
  size_t c;
  size_t d;
  // 所属的网格索引
  size_t gridid;
  // 当前四边形唯一标识ID
  size_t id;
  // 共享次面的网格索引
  size_t shareids[2];
  // 是否被共享
  bool isshared;
  QuadID()
  {
    gridid = -1;
    id     = -1;
    a = b = c = d = -1;
    shareids[0]   = -1;
    shareids[1]   = -1;
    isshared      = false;
  }
  QuadID(size_t gid, size_t aa, size_t bb, size_t cc, size_t dd) : gridid(gid), a(aa), b(bb), c(cc), d(dd)
  {
    id          = hashCombine(aa, bb, cc, dd);
    shareids[0] = -1;
    shareids[1] = -1;
    isshared    = false;
  }
};
// 单个网格
struct GridQuad
{
  // 索引
  size_t id;

  /*
    6个面

    4 5 6 7    上    quadHashID[0]
    0 1 2 3    下    quadHashID[1]
    0 3 7 4    左    quadHashID[2]
    1 2 6 5    右    quadHashID[3]
    0 1 5 4    前    quadHashID[4]
    3 2 6 7    后    quadHashID[5]
  */
  QuadID* quad[6];
};
// ID 对应的单个面
typedef unordered_map<size_t, QuadID*> MAPQUADID;
// 索引对应的单个网格
typedef unordered_map<size_t, GridQuad> MAPGRID;
// 属性数组
typedef std::vector<PropArray*> VEC_PropArray;
// 属性字段对应的属性
typedef std::map<std::string, PropArray*> MAP_PropArray;
// 消息回调函数
typedef void (*MessageStateCall)(std::string msg, int state, float per);

// 角点网格
class CornerGrid
{
public:
  CornerGrid();
  ~CornerGrid();
  // 设置回调函数
  void SetCallBack(MessageStateCall function)
  {
    mProgressFunction = function;
  }
  // 设置路径 跟 BinReader 设置的路径一致 ，去掉后缀 _geom.bin后的路径
  // 如：G:\\Data\\JD_Refined_BO3\\JD_Refined_BO3
  void SetFilePath(const std::string& path)
  {
    mFilePath = path;
  }
  // 获取路径文件
  std::string GetFilePath()
  {
    return mFilePath;
  }
  // 1 初始化数据
  void InitData();
  // 2 设置过滤信息
  // 显示指定的网格IJK
  void ShowIJKIDs(std::vector<int>& Iids, std::vector<int>& Jids, std::vector<int>& Kids);
  // 3 建立带显示网格索引,成功/失败 true/false
  bool BuildGrid();
  // 4 创建渲染数据，传入的属性数组不需要进行删除，外部删除   成功/失败 true/false
  bool GenGridRenderData(RenderData* outdata, std::vector<PropArray*>& inatts);

  // 重置查询，还原成原始的模型
  void ResetFilter();

  // 获取IJK 范围
  void GetIJKSize(vsg::ivec3& minIJK, vsg::ivec3& maxIJK);
  // 网格I方向数量
  UGINT64 SGridNI() const
  {
    return Rpt.SGridNI();
  }
  // 网格J方向数量
  UGINT64 SGridNJ() const
  {
    return Rpt.SGridNJ();
  }
  // 网格K方向数量
  UGINT64 SGridNK() const
  {
    return Rpt.SGridNK();
  }
  // 获取顶点数量
  size_t GetPointNum()
  {
    return mPointCount;
  }
  // 获取网格数量
  size_t GetGridNum()
  {
    return mGridCount;
  }
  // 获取数据偏移值
  vsg::t_vec3<double> GetOffset()
  {
    return mOffset;
  }

  // 当前显示的属性数组，由GenGridRenderData接口传入的属性数组
  // index =0 静态属性  1 ..... 动态属性的时间片
  bool GetValue(int index, std::string field, PropArray& outValues);
  // 根据当前显示的属性字段序号和IJK获取属性
  double GetValue(int index, vsg::ivec3 ijk);
  // 根据当前显示的属性字段序号获取属性范围
  bool GetValueRange(int index, double& vMin, double& vMax);

public:
  // 动态属性
  std::vector<std::vector<Name_Loc>> dym_props;  // 第N个数组存第N个时间步的所有属性
  // 静态属性
  std::vector<Name_Loc> stat_props;
  BinReader Rpt;

protected:
  // 2 设置过滤信息  debug  间隔显示
  void FilterAttDebug();
  // 2.1 剖面 [i0,i1],[j0,j1],[k0,k1]
  void FilterShowIJKSection(int i0, int i1, int j0, int j1, int k0, int k1);
  // debug
  bool Init(vsg::vec3& minVec, vsg::vec3& maxVec, std::vector<Vertex>& outVertex, std::vector<uint32_t>& indices);
  bool Init(RenderData* pData);
  // 内部执行过滤的具体实现
  void FilterInner();
  // 删除当前所有的网格面片
  void RemoveCurrent();
  // 数据路径
  std::string mFilePath;
  // 所有网格
  MAPGRID mGrids;
  // 所有待显示的网格片
  MAPQUADID mQuads;
  // 回调函数
  MessageStateCall mProgressFunction;
  // 当前的显示的属性数组
  std::vector<PropArray*> mCurrentShowAtts;
  //  激活的网格
  bool* mpActiveGrid = nullptr;
  //  顶点引用计数
  short* mpPointRefCount = nullptr;
  // 顶点个数
  size_t mPointCount = 0;
  // 网格个数
  size_t mGridCount = 0;
  // 记录的顶点信息
  PropArray GRID_VTX_array;  // 内存够？
  // 记录的网格节点信息
  PropArray NODE_LIST_array;
  // 偏移值
  vsg::t_vec3<double> mOffset;
  // 是否需要重建
  bool mNeedRebuild;
  // 转换 IJK  ID 的网格体素信息
  Voxel mVox;
};

// 多线程计算网格 内 外需要的值
class CalcWorker : public QThread
{
  Q_OBJECT
public:
  explicit CalcWorker(MAPGRID& grids, bool* active, short* pPointRefCount, PropArray* GRID_VTX_array, PropArray* NODE_LIST_array, size_t startID,
                      size_t endID);

public:
  void run();
  // 当前计算出的网格
  MAPGRID mGrids;
  // 当前计算出的网格面
  MAPQUADID mQuads;
  // 起始计算的网格索引(包含)
  size_t mStartID;
  // 结束计算的网格索引(不包含)
  size_t mEndID;
  // 顶点信息
  PropArray* pGRID_VTX_array = nullptr;
  // 节点信息
  PropArray* pNODE_LIST_array = nullptr;
  //  激活的网格
  bool* mpActiveGrid = nullptr;
  //  顶点引用计数
  short* mpPointRefCount = nullptr;
};

#endif  // !   CORNERGRID_H_